package cn.jhz.learn.blog.test.impl;

import java.util.Optional;
import java.util.Set;

import javax.validation.Valid;
import javax.validation.constraints.NotNull;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import com.google.common.collect.Sets;

import cn.jhz.learn.blog.common.exception.ParamException;
import cn.jhz.learn.blog.component.RequestHolder;
import cn.jhz.learn.blog.service.core.open.article.ArticleService;
import cn.jhz.learn.blog.service.core.open.CategoryService;
import cn.jhz.learn.blog.service.core.open.LabelService;
import cn.jhz.learn.blog.service.core.SubfieldService;


@Validated
@Service("articleService")
public class ArticleServiceImpl implements ArticleService {
	

	private final BlogArticleMapper articleMapper;

	private final LabelService labelService;

	private final CategoryService categoryService;

	private final SubfieldService subfieldService;

	@Autowired
	public ArticleServiceImpl(BlogArticleMapper articleMapper, LabelService labelService
			, CategoryService categoryService, SubfieldService subfieldService) {
		this.articleMapper = articleMapper;
		this.labelService = labelService;
		this.categoryService = categoryService;
		this.subfieldService = subfieldService;
	}

	@Override
	public Optional<BlogArticle> publishNewArticle(BlogArticle newArticle, Set<String> labelSet) {
		newArticle = Optional.ofNullable(newArticle).orElseThrow(ExceptionConstant.paramArticleIdIsNull);
		newArticle.setStatus((byte) 1);
		return save(newArticle,Optional.ofNullable(labelSet).orElseGet(Sets::newHashSet));
	}

	public Optional<BlogArticle> publishArticle(BlogArticle article, Set<String> labelSet){
		article = Optional.of(article).orElseThrow(ExceptionConstant.paramArticleIdIsNull);
		article.setStatus((byte)1);
		return modify(article,Optional.ofNullable(labelSet).orElseGet(Sets::newHashSet));
	}

	@Override
	public Optional<BlogArticle> saveDraft(BlogArticle newArticle, Set<String> labelSet) {
		newArticle = Optional.ofNullable(newArticle).orElseThrow(ExceptionConstant.paramArticleIdIsNull);
		newArticle.setStatus((byte)2);
		return save(newArticle,Optional.ofNullable(labelSet).orElseGet(Sets::newHashSet));
	}

	@Override
	public void recycleArticleById(Integer articleId) {
		Integer id = Optional.ofNullable(articleId).orElseThrow(ExceptionConstant.paramArticleIdIsNull);

		checkExist(id);
		articleMapper.updateStatusByPrimaryKey(id, (byte) 4);
		//TODO: UPDATE EXCEPTION
	}

	@Override
	public void removeArticleById(Integer articleId) {
		Integer id = Optional.ofNullable(articleId).orElseThrow(ExceptionConstant.paramArticleIdIsNull);

		checkExist(id);

		articleMapper.updateStatusByPrimaryKey(id, (byte) 0);
		//TODO: UPDATE EXCEPTION
		/**
		 * 	TODO:
		 * 	删除文章访问记录
		 * 	删除文章评论关联
		 * 	删除文章评论评分
		 * 	删除文章评分
		 * 	修改博主积分记录
		 */
	}

	@Override
	public Optional<BlogArticle> modifyArticle(BlogArticle article, Set<String> labelSet) {
		return modify(Optional.ofNullable(article).orElseThrow(ExceptionConstant.paramArticleIdIsNull)
					,Optional.ofNullable(labelSet).orElseGet(Sets::newHashSet));
	}

	@Override
	public Optional<BlogArticle> findArticleById(Integer articleId) {
		//TODO

		return Optional.empty();
	}

	private Optional<BlogArticle> save(@Valid BlogArticle article, Set<String> labelSet){
		try {
			if(article.getVisibility().equals((byte)1) && article.getStatus().equals((byte)1))
				checkContent(article.getTitle(), article.getContent().getContent());
			checkInfo(article);
			addArticle(article);

			labelService.batchAddArticleLabels(article.getId(), labelSet);
		} catch (ParamException e) {
			setDefaultValue(article);
			updateArticle(article);
			throw e;
		}
		return Optional.ofNullable(article);
	}

	private Optional<BlogArticle> modify(@Valid BlogArticle article, Set<String> labelSet) {
		//TODO:操作码
		try {
			checkExist(article.getId());
			if(article.getVisibility().equals((byte)1) && article.getStatus().equals((byte)1))
				checkContent(article.getTitle(), article.getContent().getContent());
			checkInfo(article);
			updateArticle(article);
			labelService.batchModifyArticleLabels(article.getId(), labelSet);
		} catch (ParamException e) {
			setDefaultValue(article);
			updateArticle(article);
			throw e;
		}
		return Optional.ofNullable(article);
	}

	@Override
	public BlogArticle checkExist(Integer articleId) {
		BlogArticle article = articleMapper.selectByPrimaryKey(articleId);
		if(article == null)
			throw ExceptionConstant.paramArticleIsNotExist.get();
		else if(!article.getBlogId().equals(RequestHolder.getCurrentUser().getId()) || article.getStatus() != (byte) 1)
			throw ExceptionConstant.paramArticleIsNotExist.get();
		return article;
	}

	private void checkInfo(@NotNull  BlogArticle article) {
		if(!categoryService.checkCategoryIsExistById(article.getCategoryId()))
			throw ExceptionConstant.paramCategoryIsNotExist.get();

		if(!subfieldService.checkArticleSubfieldIsExistById(article.getId()))
			throw ExceptionConstant.paramSubfieldIsNotExist.get();
	}

	private void checkContent(String title, String content) {

	}

	private void setDefaultValue(@NotNull BlogArticle article) {
		article.setCategoryId(null);
		article.setSubfieldId(null);
		article.setStatus((byte) 2);
		article.setVisibility(null);
	}

	private void addArticle(BlogArticle article) {
		articleMapper.insertSelective(article);
		article.getContent().setId(article.getId());
		articleMapper.insertContent(article.getContent());
		//TODO:INSERT EXCEPTION
	}

	private void updateArticle(BlogArticle article) {
		articleMapper.updateByPrimaryKeySelective(article);
		articleMapper.updateContent(article.getContent());
	}

}
